home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue38 / Alfresco / Graphs.pas next >
Pascal/Delphi Source File  |  1998-09-01  |  18KB  |  577 lines

  1. unit Graphs;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Classes;
  7.  
  8. type
  9.   TaaGraph = class
  10.     private
  11.       gIsDigraph : boolean;
  12.       gNodeCount : integer;
  13.     protected
  14.       function gGetEdge(aFromIndex, aToIndex : integer) : pointer; virtual; abstract;
  15.       function gGetNode(aIndex : integer) : pointer; virtual; abstract;
  16.       procedure gSetEdge(aFromIndex, aToIndex : integer;
  17.                           aValue : pointer); virtual; abstract;
  18.       procedure gSetNode(aIndex : integer; aValue : pointer); virtual; abstract;
  19.     public
  20.       constructor Create(aNodeCount : integer);
  21.  
  22.       function GetNodeEdge(aFromIndex : integer;
  23.                            aNthEdge   : integer;
  24.                        var aEdge      : pointer;
  25.                        var aToIndex   : integer) : boolean; virtual; abstract;
  26.  
  27.       property Edges[aFromIndex, aToIndex : integer] : pointer
  28.          read gGetEdge write gSetEdge;
  29.  
  30.       property IsDigraph : boolean
  31.          read gIsDigraph;
  32.  
  33.       property NodeCount : integer
  34.          read gNodeCount;
  35.  
  36.       property Nodes[aIndex : integer] : pointer
  37.          read gGetNode write gSetNode;
  38.   end;
  39.  
  40.   TaaFullMatrixGraph = class(TaaGraph)
  41.     private
  42.       mgNodes : TList;
  43.       mgEdges : TList;
  44.     protected
  45.       function gGetEdge(aFromIndex, aToIndex : integer) : pointer; override;
  46.       function gGetNode(aIndex : integer) : pointer; override;
  47.       procedure gSetEdge(aFromIndex, aToIndex : integer;
  48.                           aValue : pointer); override;
  49.       procedure gSetNode(aIndex : integer; aValue : pointer); override;
  50.  
  51.     public
  52.       constructor Create(aNodeCount : integer; aIsDigraph : boolean);
  53.       destructor Destroy; override;
  54.  
  55.       function GetNodeEdge(aFromIndex : integer;
  56.                            aNthEdge   : integer;
  57.                        var aEdge      : pointer;
  58.                        var aToIndex   : integer) : boolean; override;
  59.   end;
  60.  
  61.   TaaTriMatrixGraph = class(TaaGraph)
  62.     private
  63.       mgNodes : TList;
  64.       mgEdges : TList;
  65.     protected
  66.       function gGetEdge(aFromIndex, aToIndex : integer) : pointer; override;
  67.       function gGetNode(aIndex : integer) : pointer; override;
  68.       procedure gSetEdge(aFromIndex, aToIndex : integer;
  69.                           aValue : pointer); override;
  70.       procedure gSetNode(aIndex : integer; aValue : pointer); override;
  71.  
  72.     public
  73.       constructor Create(aNodeCount : integer);
  74.       destructor Destroy; override;
  75.  
  76.       function GetNodeEdge(aFromIndex : integer;
  77.                            aNthEdge   : integer;
  78.                        var aEdge      : pointer;
  79.                        var aToIndex   : integer) : boolean; override;
  80.   end;
  81.  
  82.   TaaLinkListGraph = class(TaaGraph)
  83.     private
  84.       lgNodes : TList;
  85.     protected
  86.       function gGetEdge(aFromIndex, aToIndex : integer) : pointer; override;
  87.       function gGetNode(aIndex : integer) : pointer; override;
  88.       procedure gSetEdge(aFromIndex, aToIndex : integer;
  89.                           aValue : pointer); override;
  90.       procedure gSetNode(aIndex : integer; aValue : pointer); override;
  91.  
  92.       procedure lgCreateEmptyLinkedList(aAtIndex : integer);
  93.       procedure lgDestroyLinkedList(aAtIndex : integer);
  94.       procedure lgSetEdgePrim(aFromIndex, aToIndex : integer;
  95.                               aValue : pointer);
  96.     public
  97.       constructor Create(aNodeCount : integer; aIsDigraph : boolean);
  98.       destructor Destroy; override;
  99.  
  100.       function GetNodeEdge(aFromIndex : integer;
  101.                            aNthEdge   : integer;
  102.                        var aEdge      : pointer;
  103.                        var aToIndex   : integer) : boolean; override;
  104.   end;
  105.  
  106. type
  107.   TaaProcessNode = procedure (aSender  : TObject;
  108.                               aNodeInx : integer);
  109.  
  110.   TaaDepthFirstIterator = class
  111.     private
  112.       dfiGraph       : TaaGraph;
  113.       dfiNodes       : TList;
  114.       dfiPostProcess : TaaProcessNode;
  115.       dfiPreProcess  : TaaProcessNode;
  116.     protected
  117.       procedure dfiDestroyCounter(aIndex : integer);
  118.     public
  119.       constructor Create(aGraph : TaaGraph);
  120.       destructor Destroy; override;
  121.  
  122.       procedure Execute(aFromIndex : integer);
  123.       procedure Reset;
  124.  
  125.       property OnPreProcess : TaaProcessNode
  126.          read dfiPreProcess write dfiPreProcess;
  127.       property OnPostProcess : TaaProcessNode
  128.          read dfiPostProcess write dfiPostProcess;
  129.   end;
  130.  
  131.  
  132. implementation
  133.  
  134. type
  135.   PllNode = ^TllNode;
  136.   TllNode = packed record
  137.     llnNext    : PllNode; // next node
  138.     llnNodeInx : integer; // node index
  139.     case boolean of
  140.       false : (llnEdge : pointer); // edge value
  141.       true  : (llnNode : pointer); // node value
  142.   end;
  143.  
  144.  
  145. constructor TaaGraph.Create(aNodeCount : integer);
  146. begin
  147.   inherited Create;
  148.   gNodeCount := aNodeCount;
  149. end;
  150.  
  151.  
  152. constructor TaaFullMatrixGraph.Create(aNodeCount : integer; aIsDigraph : boolean);
  153. begin
  154.   inherited Create(aNodeCount);
  155.   mgNodes := TList.Create;
  156.   mgNodes.Count := aNodeCount;
  157.   mgEdges := TList.Create;
  158.   mgEdges.Count := aNodeCount * aNodeCount;
  159.   gIsDigraph := aIsDigraph;
  160. end;
  161.  
  162. destructor TaaFullMatrixGraph.Destroy;
  163. begin
  164.   mgEdges.Free;
  165.   mgNodes.Free;
  166.   inherited Destroy;
  167. end;
  168.  
  169. function TaaFullMatrixGraph.GetNodeEdge(aFromIndex : integer;
  170.                                         aNthEdge   : integer;
  171.                                     var aEdge      : pointer;
  172.                                     var aToIndex   : integer) : boolean;
  173. var
  174.   i          : integer;
  175.   BeginIndex : integer;
  176. begin
  177.   Result := false;
  178.   if (aFromIndex < 0) or
  179.      (aFromIndex >= mgNodes.Count) or
  180.      (aNthEdge < 0) then
  181.     Exit;
  182.   BeginIndex := aFromIndex * NodeCount;
  183.   for i := BeginIndex to pred(BeginIndex + NodeCount) do begin
  184.     if (mgEdges[i] <> nil) then begin
  185.       if (aNthEdge = 0) then begin
  186.         Result := true;
  187.         aEdge := mgEdges[i];
  188.         aToIndex := i - BeginIndex;
  189.         Exit;
  190.       end;
  191.       dec(aNthEdge);
  192.     end;
  193.   end;
  194. end;
  195.  
  196. function TaaFullMatrixGraph.gGetEdge(aFromIndex, aToIndex : integer) : pointer;
  197. begin
  198.   if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
  199.     raise Exception.Create('TaaTriMatrixGraph.gGetEdge: from node index out of range');
  200.   if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
  201.     raise Exception.Create('TaaTriMatrixGraph.gGetEdge: to node index out of range');
  202.   Result := mgEdges[(aFromIndex * NodeCount) + aToIndex];
  203. end;
  204.  
  205. function TaaFullMatrixGraph.gGetNode(aIndex : integer) : pointer;
  206. begin
  207.   if (aIndex < 0) or (aIndex >= mgNodes.Count) then
  208.     raise Exception.Create('TaaTriMatrixGraph.gGetNode: node index out of range');
  209.   Result := mgNodes[aIndex];
  210. end;
  211.  
  212. procedure TaaFullMatrixGraph.gSetEdge(aFromIndex, aToIndex : integer;
  213.                                      aValue : pointer);
  214. begin
  215.   if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
  216.     raise Exception.Create('TaaTriMatrixGraph.gSetEdge: from node index out of range');
  217.   if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
  218.     raise Exception.Create('TaaTriMatrixGraph.gSetEdge: to node index out of range');
  219.   mgEdges[(aFromIndex * NodeCount) + aToIndex] := aValue;
  220.   if (not IsDigraph) and (aFromIndex <> aToIndex) then
  221.     mgEdges[(aToIndex * NodeCount) + aFromIndex] := aValue;
  222. end;
  223.  
  224. procedure TaaFullMatrixGraph.gSetNode(aIndex : integer; aValue : pointer);
  225. begin
  226.   if (aIndex < 0) or (aIndex >= mgNodes.Count) then
  227.     raise Exception.Create('TaaTriMatrixGraph.gSetNode: node index out of range');
  228.   mgNodes[aIndex] := aValue;
  229. end;
  230.  
  231.  
  232. constructor TaaTriMatrixGraph.Create(aNodeCount : integer);
  233. begin
  234.   inherited Create(aNodeCount);
  235.   mgNodes := TList.Create;
  236.   mgNodes.Count := aNodeCount;
  237.   mgEdges := TList.Create;
  238.   mgEdges.Count := (aNodeCount * succ(aNodeCount)) div 2;
  239. end;
  240.  
  241. destructor TaaTriMatrixGraph.Destroy;
  242. begin
  243.   mgEdges.Free;
  244.   mgNodes.Free;
  245.   inherited Destroy;
  246. end;
  247.  
  248. function TaaTriMatrixGraph.GetNodeEdge(aFromIndex : integer;
  249.                                        aNthEdge   : integer;
  250.                                    var aEdge      : pointer;
  251.                                    var aToIndex   : integer) : boolean;
  252. var
  253.   ArrayInx : integer;
  254.   ToIndex  : integer;
  255. begin
  256.   Result := false;
  257.   if (aFromIndex < 0) or
  258.      (aFromIndex >= mgNodes.Count) or
  259.      (aNthEdge < 0) then
  260.     Exit;
  261.   ArrayInx := (aFromIndex * succ(aFromIndex)) div 2;
  262.   ToIndex := 0;
  263.   {first go along horizontally along a row}
  264.   while (ToIndex <= aFromIndex) do begin
  265.     if (mgEdges[ArrayInx] <> nil) then begin
  266.       if (aNthEdge = 0) then begin
  267.         Result := true;
  268.         aEdge := mgEdges[ArrayInx];
  269.         aToIndex := ToIndex;
  270.         Exit;
  271.       end;
  272.       dec(aNthEdge);
  273.     end;
  274.     inc(ToIndex);
  275.     inc(ArrayInx);
  276.   end;
  277.   {then go vertically down a column}
  278.   inc(ArrayInx, pred(ToIndex));
  279.   while (ToIndex < NodeCount) do begin
  280.     if (mgEdges[ArrayInx] <> nil) then begin
  281.       if (aNthEdge = 0) then begin
  282.         Result := true;
  283.         aEdge := mgEdges[ArrayInx];
  284.         aToIndex := ToIndex;
  285.         Exit;
  286.       end;
  287.       dec(aNthEdge);
  288.     end;
  289.     inc(ToIndex);
  290.     inc(ArrayInx, ToIndex);
  291.   end;
  292. end;
  293.  
  294. function TaaTriMatrixGraph.gGetEdge(aFromIndex, aToIndex : integer) : pointer;
  295. var
  296.   Temp : integer;
  297. begin
  298.   if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
  299.     raise Exception.Create('TaaTriMatrixGraph.gGetEdge: from node index out of range');
  300.   if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
  301.     raise Exception.Create('TaaTriMatrixGraph.gGetEdge: to node index out of range');
  302.   if (aFromIndex < aToIndex) then begin
  303.     Temp := aFromIndex;
  304.     aFromIndex := aToIndex;
  305.     aToIndex := Temp;
  306.   end;
  307.   Result := mgEdges[(aFromIndex * succ(aFromIndex)) div 2 + aToIndex];
  308. end;
  309.  
  310. function TaaTriMatrixGraph.gGetNode(aIndex : integer) : pointer;
  311. begin
  312.   if (aIndex < 0) or (aIndex >= mgNodes.Count) then
  313.     raise Exception.Create('TaaTriMatrixGraph.gGetNode: node index out of range');
  314.   Result := mgNodes[aIndex];
  315. end;
  316.  
  317. procedure TaaTriMatrixGraph.gSetEdge(aFromIndex, aToIndex : integer;
  318.                                      aValue : pointer);
  319. var
  320.   Temp : integer;
  321. begin
  322.   if (aFromIndex < 0) or (aFromIndex >= mgNodes.Count) then
  323.     raise Exception.Create('TaaTriMatrixGraph.gSetEdge: from node index out of range');
  324.   if (aToIndex < 0) or (aToIndex >= mgNodes.Count) then
  325.     raise Exception.Create('TaaTriMatrixGraph.gSetEdge: to node index out of range');
  326.   if (aFromIndex < aToIndex) then begin
  327.     Temp := aFromIndex;
  328.     aFromIndex := aToIndex;
  329.     aToIndex := Temp;
  330.   end;
  331.   mgEdges[(aFromIndex * succ(aFromIndex)) div 2 + aToIndex] := aValue;
  332. end;
  333.  
  334. procedure TaaTriMatrixGraph.gSetNode(aIndex : integer; aValue : pointer);
  335. begin
  336.   if (aIndex < 0) or (aIndex >= mgNodes.Count) then
  337.     raise Exception.Create('TaaTriMatrixGraph.gSetNode: node index out of range');
  338.   mgNodes[aIndex] := aValue;
  339. end;
  340.  
  341.  
  342. constructor TaaLinkListGraph.Create(aNodeCount : integer; aIsDigraph : boolean);
  343. var
  344.   i : integer;
  345. begin
  346.   inherited Create(aNodeCount);
  347.   lgNodes := TList.Create;
  348.   lgNodes.Count := aNodeCount;
  349.   for i := 0 to pred(aNodeCount) do
  350.     lgCreateEmptyLinkedList(i);
  351.   gIsDigraph := aIsDigraph;
  352. end;
  353.  
  354. destructor TaaLinkListGraph.Destroy;
  355. var
  356.   i : integer;
  357. begin
  358.   for i := 0 to pred(NodeCount) do
  359.     lgDestroyLinkedList(i);
  360.   lgNodes.Free;
  361.   inherited Destroy;
  362. end;
  363.  
  364. function TaaLinkListGraph.GetNodeEdge(aFromIndex : integer;
  365.                                       aNthEdge   : integer;
  366.                                   var aEdge      : pointer;
  367.                                   var aToIndex   : integer) : boolean;
  368. var
  369.   WalkNode : PllNode;
  370. begin
  371.   Result := false;
  372.   if (aFromIndex < 0) or
  373.      (aFromIndex >= lgNodes.Count) or
  374.      (aNthEdge < 0) then
  375.     Exit;
  376.   WalkNode := lgNodes[aFromIndex];
  377.   while (WalkNode <> nil) and (aNthEdge >= 0) do begin
  378.     WalkNode := WalkNode^.llnNext;
  379.     dec(aNthEdge);
  380.   end;
  381.   if (WalkNode = nil) or (WalkNode^.llnNext = nil) then
  382.     Exit;
  383.   Result := true;
  384.   aEdge := WalkNode^.llnEdge;
  385.   aToIndex := WalkNode^.llnNodeInx;
  386. end;
  387.  
  388. function TaaLinkListGraph.gGetEdge(aFromIndex, aToIndex : integer) : pointer;
  389. var
  390.   WalkNode : PllNode;
  391. begin
  392.   if (aFromIndex < 0) or (aFromIndex >= lgNodes.Count) then
  393.     raise Exception.Create('TaaLinkListGraph.gSetEdge: from node index out of range');
  394.   if (aToIndex < 0) or (aToIndex >= lgNodes.Count) then
  395.     raise Exception.Create('TaaLinkListGraph.gSetEdge: to node index out of range');
  396.   Result := nil;
  397.   WalkNode := lgNodes[aFromIndex];
  398.   while (WalkNode^.llnNodeInx < aToIndex) do
  399.     WalkNode := WalkNode^.llnNext;
  400.   if (WalkNode^.llnNodeInx = aToIndex) then
  401.     Result := WalkNode^.llnEdge;
  402. end;
  403.  
  404. function TaaLinkListGraph.gGetNode(aIndex : integer) : pointer;
  405. begin
  406.   if (aIndex < 0) or (aIndex >= lgNodes.Count) then
  407.     raise Exception.Create('TaaLinkListGraph.gGetNode: node index out of range');
  408.   Result := PllNode(lgNodes[aIndex])^.llnNode;
  409. end;
  410.  
  411. procedure TaaLinkListGraph.gSetEdge(aFromIndex, aToIndex : integer;
  412.                                     aValue : pointer);
  413. begin
  414.   if (aFromIndex < 0) or (aFromIndex >= lgNodes.Count) then
  415.     raise Exception.Create('TaaLinkListGraph.gSetEdge: from node index out of range');
  416.   if (aToIndex < 0) or (aToIndex >= lgNodes.Count) then
  417.     raise Exception.Create('TaaLinkListGraph.gSetEdge: to node index out of range');
  418.   lgSetEdgePrim(aFromIndex, aToIndex, aValue);
  419.   if (not IsDigraph) and (aFromIndex <> aToIndex) then
  420.     lgSetEdgePrim(aToIndex, aFromIndex, aValue);
  421. end;
  422.  
  423. procedure TaaLinkListGraph.gSetNode(aIndex : integer; aValue : pointer);
  424. begin
  425.   if (aIndex < 0) or (aIndex >= lgNodes.Count) then
  426.     raise Exception.Create('TaaLinkListGraph.gSetNode: node index out of range');
  427.   PllNode(lgNodes[aIndex])^.llnNode := aValue;
  428. end;
  429.  
  430. procedure TaaLinkListGraph.lgCreateEmptyLinkedList(aAtIndex : integer);
  431. var
  432.   FirstNode : PllNode;
  433.   LastNode : PllNode;
  434. begin
  435.   New(LastNode);
  436.   with LastNode^ do begin
  437.     llnNext := nil;
  438.     llnEdge := nil;
  439.     llnNodeInx := $7FFFFFFF; // greater than any node index
  440.   end;
  441.   New(FirstNode);
  442.   with FirstNode^ do begin
  443.     llnNext := LastNode;
  444.     llnNode := nil;
  445.     llnNodeInx := -1; // less than any node index
  446.   end;
  447.   lgNodes[aAtIndex] := FirstNode;
  448. end;
  449.  
  450. procedure TaaLinkListGraph.lgDestroyLinkedList(aAtIndex : integer);
  451. var
  452.   Dad, Son : PllNode;
  453. begin
  454.   Son := lgNodes[aAtIndex];
  455.   while (Son <> nil) do begin
  456.     Dad := Son;
  457.     Son := Dad^.llnNext;
  458.     Dispose(Dad);
  459.   end;
  460. end;
  461.  
  462. procedure TaaLinkListGraph.lgSetEdgePrim(aFromIndex, aToIndex : integer;
  463.                                          aValue : pointer);
  464. var
  465.   DadNode, WalkNode, NewNode : PllNode;
  466. begin
  467.   DadNode := nil;
  468.   WalkNode := lgNodes[aFromIndex];
  469.   while (WalkNode^.llnNodeInx < aToIndex) do begin
  470.     DadNode := WalkNode;
  471.     WalkNode := DadNode^.llnNext;
  472.   end;
  473.   if (WalkNode^.llnNodeInx = aToIndex) then
  474.     WalkNode^.llnEdge := aValue
  475.   else begin
  476.     New(NewNode);
  477.     with NewNode^ do begin
  478.       llnNext := WalkNode;
  479.       llnEdge := aValue;
  480.       llnNodeInx := aToIndex;
  481.     end;
  482.     DadNode^.llnNext := NewNode;
  483.   end;
  484. end;
  485.  
  486.  
  487. type
  488.   PdfiCounter = ^TdfiCOunter;
  489.   TdfiCounter = packed record
  490.     cMarker : integer;
  491.     cParent : integer;
  492.     cLevel  : integer;
  493.   end;
  494.  
  495. constructor TaaDepthFirstIterator.Create(aGraph : TaaGraph);
  496. var
  497.   i : integer;
  498. begin
  499.   inherited Create;
  500.   dfiGraph := aGraph;
  501.   dfiNodes := TList.Create;
  502.   dfiNodes.Count := aGraph.NodeCount;
  503.   for i := 0 to pred(dfiNodes.Count) do
  504.     dfiNodes[i] := AllocMem(sizeof(TdfiCounter));
  505.   Reset;
  506. end;
  507.  
  508. destructor TaaDepthFirstIterator.Destroy;
  509. var
  510.   i : integer;
  511. begin
  512.   for i := 0 to pred(dfiNodes.Count) do
  513.     dfiDestroyCounter(i);
  514.   inherited Destroy;
  515. end;
  516.  
  517. procedure TaaDepthFirstIterator.dfiDestroyCounter(aIndex : integer);
  518. var
  519.   Counter : PdfiCounter;
  520. begin
  521.   Counter := dfiNodes[aIndex];
  522.   if (Counter <> nil) then
  523.     Dispose(Counter);
  524. end;
  525.  
  526. procedure TaaDepthFirstIterator.Execute(aFromIndex : integer);
  527. var
  528.   i          : integer;
  529.   NewNodeInx : integer;
  530.   Edge       : pointer;
  531.   OurLevel   : integer;
  532. begin
  533.   // perform preprocessing on the node
  534.   if Assigned(dfiPreProcess) then
  535.     dfiPreProcess(Self, aFromIndex);
  536.   // mark the node as preprocessed
  537.   with PdfiCounter(dfiNodes[aFromIndex])^ do begin
  538.     cMarker := 1;
  539.     OurLevel := cLevel;
  540.   end;
  541.   // iterate through the edges from this node
  542.   i := 0;
  543.   while dfiGraph.GetNodeEdge(aFromIndex, i, Edge, NewNodeInx) do begin
  544.     with PdfiCounter(dfiNodes[NewNodeInx])^ do begin
  545.       if (cMarker = 0) then begin
  546.         cParent := aFromIndex;
  547.         cLevel := succ(OurLevel);
  548.         Execute(NewNodeInx);
  549.       end;
  550.     end;
  551.     inc(i);
  552.   end;
  553.   // perform postprocessing on the node
  554.   if Assigned(dfiPostProcess) then
  555.     dfiPostProcess(Self, aFromIndex);
  556.   // mark the node as postprocessed
  557.   with PdfiCounter(dfiNodes[aFromIndex])^ do begin
  558.     cMarker := 2;
  559.   end;
  560. end;
  561.  
  562. procedure TaaDepthFirstIterator.Reset;
  563. var
  564.   i : integer;
  565. begin
  566.   for i := 0 to pred(dfiNodes.Count) do begin
  567.     with PdfiCounter(dfiNodes[i])^ do begin
  568.       cMarker := 0;
  569.       cParent := -1;
  570.       cLevel  := 0;
  571.     end;
  572.   end;
  573. end;
  574.  
  575.  
  576. end.
  577.